// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#pragma hdrstop

#include "stdafx.h"
#include "netlistmgr.h"
#include "sample.h"
#include "utils.h"

#define  NUM_NETWORK		10		// number of networks to fetch at one time
#define  NUM_CONNECTION		10		// number of networks to fetch at one time
#define  MAX_LENGTH			1024	// number of networks to fetch at one time

//
// FUNCTION: EventTest
//
// Sets up 3 NLM event sinks through the CEventSink class. We can chose to
// only listen to a partial subset of the events if desired.
//
// CEventSink implements the event listener through an STA thread with a 
// message loop.
//
/*HRESULT EventTest()
{
	HRESULT hr = S_OK;

	CEventSink* pEventSink1;
	CEventSink* pEventSink2;
	CEventSink* pEventSink3;
	bool bIsConnected = FALSE;

	HRESULT hrCoinit = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (SUCCEEDED(hrCoinit) || (RPC_E_CHANGED_MODE == hrCoinit))
	{
		// scope for CComPtr<INetworkListManager>
		{
			CComPtr<INetworkListManager> pNLM;
			hr = CoCreateInstance(CLSID_NetworkListManager, 
				NULL, CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNLM);
			if(hr == S_OK)
			{
				hr = CEventSink::StartListeningForEvents(IID_INetworkConnectionEvents, &pEventSink1);
				if (SUCCEEDED(hr))
				{
					hr = CEventSink::StartListeningForEvents(IID_INetworkEvents, &pEventSink2);
					if (SUCCEEDED(hr))
					{
						hr = CEventSink::StartListeningForEvents(IID_INetworkListManagerEvents, &pEventSink3);
						if (SUCCEEDED(hr))
						{
							wprintf(L"Listening for events. \r\n");
							int i;
							wprintf(L"Press a key and enter to stop: " );
							scanf_s( "%d", &i );                        
							//Sleep(5000);
							pEventSink3->StopListeningForEvents();
							pEventSink3->Release();
						}
						pEventSink2->StopListeningForEvents();
						pEventSink2->Release();
					}
					pEventSink1->StopListeningForEvents();
					pEventSink1->Release();
				}
			}
		}

		if (RPC_E_CHANGED_MODE != hrCoinit)
		{
			CoUninitialize();
		}
	}
	return hr;
}*/

//The domain type of network is printed.
VOID PrintDomainTypeString (NLM_DOMAIN_TYPE DomainType)
{
	switch( DomainType )
	{
	case NLM_DOMAIN_TYPE_NON_DOMAIN_NETWORK:
		wprintf( L"NLM_DOMAIN_TYPE_NON_DOMAIN_NETWORK\n" );
		break;

	case NLM_DOMAIN_TYPE_DOMAIN_NETWORK:
		wprintf( L"NLM_DOMAIN_TYPE_DOMAIN_NETWORK\n" );
		break;

	case NLM_DOMAIN_TYPE_DOMAIN_AUTHENTICATED:
		wprintf( L"NLM_DOMAIN_TYPE_DOMAIN_AUTHENTICATED\n" );
		break;

	default:
		wprintf( L"%d\n", (DWORD)DomainType );
	}

	return;
}



VOID PrintCategoryString (NLM_NETWORK_CATEGORY Category)
{
	switch( Category )
	{
	case NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED:
		wprintf( L"NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED\n" );
		break;

	case NLM_NETWORK_CATEGORY_PRIVATE:
		wprintf( L"NLM_NETWORK_CATEGORY_PRIVATE\n" );
		break;

	case NLM_NETWORK_CATEGORY_PUBLIC:
		wprintf( L"NLM_NETWORK_CATEGORY_PUBLIC\n" );
		break;

	default:
		wprintf( L"%d\n", (DWORD)Category );
	}

	return;
}

HRESULT PrintNetworkConnectivity(INetwork* pNetwork)
{
	HRESULT hr = S_OK;
	if(pNetwork != NULL)
	{
		NLM_CONNECTIVITY nlmConnectivity;
		hr = pNetwork->GetConnectivity(&nlmConnectivity);
		CComBSTR szConnectivity = L"";
		if( hr == S_OK)
		{
			if (nlmConnectivity == NLM_CONNECTIVITY_DISCONNECTED)
			{
				szConnectivity = L"network disconnected";
			}

			if (nlmConnectivity & NLM_CONNECTIVITY_IPV4_NOTRAFFIC)
			{
				if (szConnectivity.Length() != 0)
				{
					szConnectivity += L" | ";
				}
				szConnectivity += L"network no traffic";
			}

			if (nlmConnectivity & NLM_CONNECTIVITY_IPV4_LOCALNETWORK)
			{
				if (szConnectivity.Length() != 0)
				{
					szConnectivity += L" | ";
				}
				szConnectivity += L"IPv4 local connectivity";
			}

			if (nlmConnectivity & NLM_CONNECTIVITY_IPV4_INTERNET)
			{
				if (szConnectivity.Length() != 0)
				{
					szConnectivity += L" | ";
				}
				szConnectivity += L"IPv4 internet connectivity";
			}

			if (nlmConnectivity & NLM_CONNECTIVITY_IPV6_LOCALNETWORK)
			{
				if (szConnectivity.Length() != 0)
				{
					szConnectivity += L" | ";
				}
				szConnectivity += L"IPv6 local connectivity";
			}

			if (nlmConnectivity & NLM_CONNECTIVITY_IPV6_INTERNET)
			{
				if (szConnectivity.Length() != 0)
				{
					szConnectivity +=   L" | ";
				}
				szConnectivity += L"IPv6 internet connectivity";
			}
		}
		if (SUCCEEDED(hr))
		{
			WCHAR result[MAX_LENGTH];
			wcscpy_s(result, _countof(result), szConnectivity);
			wprintf(L"Network Connectivity bitmask           : 0x%08x %s\n", nlmConnectivity, result);
		}
		else
		{
			wprintf(L"failed to get connectivity from INetwork ");
		}
	}
	return hr;
}
//
// FUNCTION: ShowInfoForNetworkConnection
//
// Prints out all the properties related to a specific INetworkConnection
//
void ShowInfoForNetworkConnection(INetworkConnection* pNetworkConnection)
{
	HRESULT hr = S_OK;

	GUID gdConnectionId;
	hr = pNetworkConnection->GetConnectionId(&gdConnectionId);
	if (SUCCEEDED(hr))
	{
		wprintf(L"    Connection Id              : %s\n", GetSzGuid(gdConnectionId));
	}

	GUID gdAdapterId;
	hr = pNetworkConnection->GetAdapterId(&gdAdapterId);
	if (SUCCEEDED(hr))
	{
		BSTR szAdapterIDName =  GetSzGuid(gdAdapterId);
		wprintf(L"    Adapter Id                 : %s\n", szAdapterIDName);
	}


	VARIANT_BOOL bNetworkIsConnected;
	hr = pNetworkConnection->get_IsConnected(&bNetworkIsConnected);
	if (SUCCEEDED(hr))
	{
		LPCWSTR sBool = (bNetworkIsConnected == VARIANT_TRUE) ? L"TRUE" : L"FALSE";
		wprintf(L"    Connected to Network       : %s\n", sBool);
	}

	VARIANT_BOOL bNetworkIsConnectedToInternet;
	hr = pNetworkConnection->get_IsConnectedToInternet(&bNetworkIsConnectedToInternet);
	if (SUCCEEDED(hr))
	{
		LPCWSTR sBool = (bNetworkIsConnectedToInternet == VARIANT_TRUE) ? L"TRUE" : L"FALSE";
		wprintf(L"    Connected to Internet      : %s\n", sBool);
	}

	// IMPORTANT: Connectivity is a bitmask
	NLM_CONNECTIVITY fConnectivity;
	hr = pNetworkConnection->GetConnectivity(&fConnectivity);
	if (SUCCEEDED(hr))
	{
		wprintf(L"    Connectivity bitmask       : 0x%08x (%s)\r\n", fConnectivity, NLM_CONNECTIVITY_ToString(fConnectivity));
	}

	NLM_DOMAIN_TYPE eDomainType;
	hr = pNetworkConnection->GetDomainType(&eDomainType);
	if ( hr == S_OK )
	{
		wprintf(L"    Connection domain type: " );
		PrintDomainTypeString( eDomainType );
	}
}

//
// FUNCTION: ShowNetworkConnections
//
// Cycles through all NetworkConnections in pEnum and pass them to ShowInfoForNetworkConnection
//
void ShowNetworkConnections(IEnumNetworkConnections* pEnum)
{
	HRESULT hr = S_OK;

	INetworkConnection* pNetworkConnections[NUM_CONNECTION];
	ULONG cFetched = 0;
	BOOL  bDone = FALSE;
	while (!bDone)
	{
		hr = pEnum->Next(_countof(pNetworkConnections), pNetworkConnections, &cFetched);
		if (SUCCEEDED(hr) && (cFetched > 0))
		{
			for (ULONG i = 0; i < cFetched; i++)
			{
				ShowInfoForNetworkConnection(pNetworkConnections[i]);
				pNetworkConnections[i]->Release();
			}
		}
		else
		{
			bDone = TRUE;
		}
	}
}

//
// FUNCTION: ShowInfoForNetwork
//
// Prints out the properties for a given INetwork
//
void ShowInfoForNetwork(INetwork* pNetwork)
{
	HRESULT hr = S_OK;

	CComBSTR szName;
	hr = pNetwork->GetName(&szName);
	if (SUCCEEDED(hr))
	{
		wprintf(L"Network Name                   : %s\n", szName);
	}

	CComBSTR szDescription;
	hr = pNetwork->GetDescription(&szDescription);
	if (SUCCEEDED(hr))
	{
		wprintf(L"Network Description            : %s\n", szDescription);
	}

	VARIANT_BOOL bNetworkIsConnected;
	hr = pNetwork->get_IsConnected(&bNetworkIsConnected);
	if (SUCCEEDED(hr))
	{
		LPCWSTR sBool = (bNetworkIsConnected == VARIANT_TRUE) ? L"TRUE" : L"FALSE";
		wprintf(L"Connected to Network          : %s\n", sBool);
	}

	VARIANT_BOOL bNetworkIsConnectedToInternet;
	hr = pNetwork->get_IsConnectedToInternet(&bNetworkIsConnectedToInternet);
	if (SUCCEEDED(hr))
	{
		LPCWSTR sBool = (bNetworkIsConnectedToInternet == VARIANT_TRUE) ? L"TRUE" : L"FALSE";
		wprintf(L"Connected to Internet          : %s\n", sBool);
	}

	// IMPORTANT: Connectivity is a bitmask
	PrintNetworkConnectivity(pNetwork);


	//Whether this network is connected to domain network directly
	NLM_DOMAIN_TYPE DomainType;
	hr = pNetwork->GetDomainType( &DomainType );
	if ( hr == S_OK )
	{
		wprintf(L"Network domain type: " );
		PrintDomainTypeString( DomainType );
	}
	else
	{
		wprintf (L"INetwork::GetDomainType failed, hr = %#x\n", hr );
	}


	NLM_NETWORK_CATEGORY Category;
	hr = pNetwork->GetCategory( &Category );
	if ( hr == S_OK )
	{
		wprintf(L"Network Category: " );
		PrintCategoryString ( Category );
	}
	else
	{
		wprintf (L"INetwork::GetCategory failed, hr = %#x\n", hr );
	}

	GUID gdNetworkId;
	hr = pNetwork->GetNetworkId(&gdNetworkId);
	if (SUCCEEDED(hr))
	{
		wprintf(L"Network Id                     : %s\n", GetSzGuid(gdNetworkId));
	}

	CComPtr<IEnumNetworkConnections> pNetworkConnections;
	hr = pNetwork->GetNetworkConnections(&pNetworkConnections);
	if (SUCCEEDED(hr))
	{
		ShowNetworkConnections(pNetworkConnections);
	}
}

//
// FUNCTION: ShowNetworks
// 
// Enumerates over all the connected networks and dump out information
// on each one of them
//
void ShowNetworks()
{
	HRESULT hr = S_OK;
	HRESULT hrCoinit = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (SUCCEEDED(hrCoinit) || (RPC_E_CHANGED_MODE == hrCoinit))
	{
		// scope for CComPtr<INetworkListManager>
		{
			CComPtr<INetworkListManager> pNLM;
			hr = CoCreateInstance(CLSID_NetworkListManager, NULL, 
				CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNLM);
			if (SUCCEEDED(hr))
			{
				CComPtr<IEnumNetworks> pEnumNetworks;

				// Enumerate connected networks 
				hr = pNLM->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, &pEnumNetworks);
				if (SUCCEEDED(hr))
				{
					INetwork* pNetworks[NUM_NETWORK];
					ULONG cFetched = 0;
					BOOL  bDone = FALSE;
					while (!bDone)
					{             
						hr = pEnumNetworks->Next(_countof(pNetworks), pNetworks, &cFetched);
						if (SUCCEEDED(hr) && (cFetched > 0))
						{
							for (ULONG i = 0; i < cFetched; i++)
							{
								ShowInfoForNetwork(pNetworks[i]);
								pNetworks[i]->Release();
							}
						}
						else
						{
							bDone = TRUE;
						}
					}
				}
			}
			else
			{
				wprintf( L"Failed to CoCreate INetworkListManager");
			}
		}

		if (RPC_E_CHANGED_MODE != hrCoinit)
		{
			CoUninitialize();
		}
	}
	else
	{
		hr = hrCoinit;
	}
}

//
//  FUNCTION: IsConnected
// 
//  'Hello World' function - returns whether we're connected to any network.
//
HRESULT IsConnected(LPBOOL pbIsConnected)
{
	if (!pbIsConnected)
	{
		return E_POINTER;
	}

	*pbIsConnected = FALSE;

	HRESULT hr = S_OK;
	HRESULT hrCoinit = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (SUCCEEDED(hrCoinit) || (RPC_E_CHANGED_MODE == hrCoinit))
	{
		// scope for CComPtr<INetworkListManager>
		{
			CComPtr<INetworkListManager> pNLM;
			hr = CoCreateInstance(CLSID_NetworkListManager, 
				NULL, CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNLM);
			if (SUCCEEDED(hr))
			{
				VARIANT_BOOL bIsConnected;

				// Checks if we can see any network.
				// Change this to get_IsConnectedToInternet if it is important
				// to find out whether the machine is connected to the internet
				// as opposed to just a local network.
				HRESULT hrtemp = pNLM->get_IsConnected(&bIsConnected);
				if (SUCCEEDED(hrtemp))
				{
					*pbIsConnected = (bIsConnected == VARIANT_TRUE);
				}
			}
		}

		if (RPC_E_CHANGED_MODE != hrCoinit)
		{
			CoUninitialize();
		}
	}
	else
	{
		hr = hrCoinit;
	}

	return hr;
}

CComModule _Module;
/*
//extern "C" void __cdecl main()
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;

BOOL bIsConnected;
hr = IsConnected(&bIsConnected);
if (SUCCEEDED(hr))
{
wprintf(L"Machine is %s to a network\r\n", bIsConnected ? L"connected" : L"not connected");
}
ShowNetworks();
EventTest();
wprintf(L" leaving ....");
}
*/
